import cn.gzzhome.utils.Move
import cn.gzzhome.utils.ScmHelper
import cn.gzzhome.utils.ScmTask
import cn.gzzhome.utils.Task
import com.cloudbees.groovy.cps.NonCPS
import groovy.transform.Field
import hudson.scm.ChangeLogSet

/**
 * autoPipeline 即Auto Pipeline的缩写，也是为了容易记住
 * <br>
 *     此工具用于快速定义生产线，实现低代码部署项目
 * <br>
 *     每个任务包含了四个阶段：构建、测试、部署、验收（后续可扩展）
 * <br>
 *     任务结构：
 *     <ul>
 *         <li>name: 任务名，唯一的</li>
 *         <li>remark: 任务备注，用于说明任务的用途及基本结构，便于后来维护者可以快速了解情况</li>
 *         <li>dependence: 项目依赖，可以有多个依赖，以便系统自动触发相关的任务</li>
 *         <li>pathDependence: 路径依赖，用于定义项目中依赖的路径</li>
 *     </ul>
 */

@Field
List<Task> taskList = []

@Field
ScmHelper scmHelper = null

/**
 * 构建历史文件名
 */
@Field
String historyFileName = ".build_history"

/**
 * 最多可同时进行多少个步骤，默认为3个
 */
@Field
int maxMoveCount = 3

/**
 * 设置最大执行个数
 * @param count
 * @return
 */
def maxMove(int count) {
    maxMoveCount = count
}

/**
 * 添加任务
 * @param name
 * @param cb
 * @return
 */
def task(String name, Closure cb) {
    println("进task了")
    Task task = new Task()
    task.init(name, cb)
    taskList += task
}

/**
 * 添加自动构建任务
 * @param name
 * @param cb
 */
def scmTask(String name, Closure cb) {
    if (scmHelper == null) {
        scmHelper = new ScmHelper()
        scmHelper.initChangeList(currentBuild)
    }
    Task task = new ScmTask()
    task.scmHelper = scmHelper
    task.init(name, cb)
    taskList += task
}

/**
 * 获取并排序moves
 * @param tasks
 * @return
 */
@NonCPS
List<Move> getMoves(List<Task> tasks) {
    //将所有的步骤保存到一个列表中
    List<Move> moves = []
    Map<Integer, List<Task>> taskGroup = tasks.groupBy {
        it.level
    }
    List<Integer> levels = taskGroup.keySet() as List
    levels.sort()
    //排序所有的步骤
    levels.each {
        level ->
            List<Task> taskList = taskGroup.get(level)
            List<Move> tmpMoves = []
            taskList.each { tmpMoves += it.moveList }
            tmpMoves.sort { it.idx }
            moves += tmpMoves
    }
    return moves
}

/**
 * 执行任务
 * @param tasks
 */
def process(List<Task> tasks) {
    List<Move> moves = getMoves(tasks)
    println "maxMoveCount=${maxMoveCount}"
    //执行所有的步骤
    def p = 0
    def runningMoves = [failFast: true]
    boolean block = false
    def stageIdx = 0
    while (p < moves.size()) {
        Move move = moves[p++]
        println("[name=${move.name},block=${move.block},task=${move.task},idx=${move.idx},level=${move.getLevel()}]")
        runningMoves[move.name] = { move.run() }
        if (move.block) {
            block = true
        }
        if (runningMoves.size() > maxMoveCount  //超过最大的步骤数
                || p >= moves.size()    //已经结束
                || move.task.name == moves[p].task.name   //下一个步骤是同一个任务
//                || (move.getLevel() == moves[p].getLevel() && move.idx != moves[p].idx)
                || (block && moves[p].getLevel() != move.getLevel())) {
            stage("阶段${stageIdx++}") {
                println(runningMoves)
                parallel(runningMoves)
            }
            runningMoves = [failFast: true]
            block = false
        }
    }

}

def call(Closure cb) {
    cb.resolveStrategy = Closure.DELEGATE_FIRST
    cb.delegate = this
    try {
        cb()
    } catch (Exception e) {
        Utils { printError(e) }
        throw e
    }
    echo "changeFiles=${scmHelper.changeFiles}"
    echo "preChangeFiles=${scmHelper.preChangeFiles}"
    echo "lastBuild=${scmHelper.lastSuccessBuild},lastBuildNum=${scmHelper.lastSuccessBuild.number}"
    scmHelper.lastSuccessBuild.changeSets.each{
        it.each {
            def entity = it as ChangeLogSet.Entry
            echo "${entity.affectedPaths}"
        }
    }
    echo "currentBuild=${scmHelper.currentBuild}"
    //读取历史文件
    def history = [:]
    if (fileExists(historyFileName)) {
        try {
            history = Utils { readJsonFile(historyFileName) }
        } catch (Exception e) {
            echo "读取历史文件失败！"
        }
    }
    //查找所有需要构建的项目
    def needProcessTasks = taskList.findAll {
        echo "task=${it.getClass()},needProcess=${it.needProcess()},history=${history[it.name]},dependOnList=${it.dependOnList}"
        if (ScmTask.class.isAssignableFrom(it.getClass())) {
            echo "isChange=${it.isChange()},hasChange=${it.hasChange()}"
        }
        def flag = it.needProcess() || (!history[it.name])
        if (!flag) {
            flag = !history[it.name].success
        }
        return flag
    }
    //添加一个动作以记录历史
    needProcessTasks.each {
        task ->
            history.remove(task.name)
            task.move("_save_his_") {
                def result = ["lastRunTime": new Date(), "success": true, "buildNumber": "${env.BUILD_NUMBER}"]
                history[task.name] = result
                Utils { writeJsonFile(historyFileName, history) }
            }
    }
    Utils { writeJsonFile(historyFileName, history) }
    process(needProcessTasks)
}